/*
  Copyright (C) 2011, Kyungjoo Kim
  
  This file is part of LINAL (LINear ALgebra)
  
  All rights reserved.

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.
  
  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.
  
  You should have received a copy of the GNU Lesser General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  Also add information on how to contact you by electronic and paper mail.
  
  
  Kyungjoo Kim
  iamkyungjoo@gmail.com
*/
#ifndef LINAL_DEVICE_HOST_OPERATION_HXX
#define LINAL_DEVICE_HOST_OPERATION_HXX

/*! 
  Operations for the flat matrix on host device
*/ 
namespace linal      {
  namespace host   { 
    namespace internal {
      // * Utilities

      extern Int_ norm1    ( FLA_Obj &A, FLA_Obj &norm );
      extern Int_ norm1    ( Int_ uplo, Int_ diag, FLA_Obj &A, FLA_Obj &norm );


      //**** NOT YET implemented 
      // inverse norm is used for the condition number of triangular square matrix
      extern Int_ inv_norm1( Int_ uplo, Int_ diag, FLA_Obj &A, FLA_Obj &norm );
      extern Int_ inv_norm1( Double_ sample, 
                            Int_ uplo, Int_ diag, FLA_Obj &A, FLA_Obj &norm );
      
      //**** IMPLEMENTED
      extern Int_ apply_diag_scal       ( Int_ side, Int_ conj, Int_ inv, Int_ uplo, 
                                          FLA_Obj &A );
      extern Int_ apply_diag_scal       ( Int_ side, Int_ conj, Int_ uplo, FLA_Obj &A );
      extern Int_ apply_diag_inv_scal   ( Int_ side, Int_ conj, Int_ uplo, FLA_Obj &A );

      extern Int_ apply_diag_scal       ( Int_ side, Int_ conj, Int_ inv, 
                                          FLA_Obj &A, FLA_Obj &B );
      extern Int_ apply_diag_scal       ( Int_ side, Int_ conj, FLA_Obj &A, FLA_Obj &B );
      extern Int_ apply_diag_inv_scal   ( Int_ side, Int_ conj, FLA_Obj &A, FLA_Obj &B );

      extern Int_ apply_pivots_ln ( FLA_Obj &p, FLA_Obj &A);
      extern Int_ apply_pivots_lt ( FLA_Obj &p, FLA_Obj &A);
      extern Int_ apply_pivots_rn ( FLA_Obj &p, FLA_Obj &A);
      extern Int_ apply_pivots_rt ( FLA_Obj &p, FLA_Obj &A);
      
      extern Int_ apply_pivots    ( Int_ side, Int_ trans, 
                                   FLA_Obj &p, FLA_Obj &A);


      extern Int_ apply_q_ut      ( Int_ side, Int_ trans, Int_ direct, Int_ storev,
                                   FLA_Obj &A, FLA_Obj &T, 
                                   FLA_Obj &W, FLA_Obj &B );

      extern Int_ apply_q2_ut     ( Int_ side, Int_ trans, Int_ direct, Int_ storev,
                                   FLA_Obj &D, FLA_Obj &T, 
                                   FLA_Obj &W, FLA_Obj &C,
                                   FLA_Obj &E );
      
      extern Int_ get_diag        ( FLA_Obj &A, FLA_Obj &d );
      extern Int_ set_diag        ( FLA_Obj &d, FLA_Obj &A );

      /*
      extern Int_ invert          ( Int_ conj, FLA_Obj &x );
      extern Int_ conjugate       ( FLA_Obj &A );

      extern Int_ hermitianize    ( Int_ uplo, FLA_Obj &A);
      extern Int_ symmetrize      ( Int_ uplo, FLA_Obj &A);

      extern Int_ copy            ( FLA_Obj &A, FLA_Obj &B );
      extern Int_ copyt           ( FLA_Obj &A, FLA_Obj &B );
      extern Int_ axpy            ( Int_ trans, FLA_Obj &A, FLA_Obj &B );
      */


      // * BLAS
      extern Int_ herk            ( Int_ uplo, Int_ trans,
                                   FLA_Obj &alpha, FLA_Obj &A,
                                   FLA_Obj &beta,  FLA_Obj &C );
      extern Int_ syrk            ( Int_ uplo, Int_ trans,
                                   FLA_Obj &alpha, FLA_Obj &A,
                                   FLA_Obj &beta,  FLA_Obj &C );
      extern Int_ gemm            ( Int_ transa, Int_ transb,
                                   FLA_Obj &alpha, FLA_Obj &A, FLA_Obj &B,
                                   FLA_Obj &beta,  FLA_Obj &C );
      extern Int_ trsm            ( Int_ side, Int_ uplo, Int_ trans, Int_ diag,
                                   FLA_Obj &alpha, FLA_Obj &A, FLA_Obj &B );
      extern Int_ trmm            ( Int_ side, Int_ uplo, Int_ trans, Int_ diag,
                                   FLA_Obj &alpha, FLA_Obj &A, FLA_Obj &B );
      
      // * FLAME
      extern Int_ chol_nopiv   ( Int_ uplo, FLA_Obj &A );
      extern Int_ chol_piv_l   ( FLA_Obj &A, FLA_Obj &p );
      extern Int_ chol_piv_u   ( FLA_Obj &A, FLA_Obj &p );
      extern Int_ chol_piv     ( Int_ uplo, FLA_Obj &A, FLA_Obj &p );
      
      extern Int_ ldl_nopiv_l  ( FLA_Obj &A );
      extern Int_ ldl_nopiv_u  ( FLA_Obj &A );
      extern Int_ ldl_nopiv    ( Int_ uplo, FLA_Obj &A );
      
      extern Int_ ldl_piv_l    ( FLA_Obj &A, FLA_Obj &p );
      extern Int_ ldl_piv_u    ( FLA_Obj &A, FLA_Obj &p );
      extern Int_ ldl_piv      ( Int_ uplo, FLA_Obj &A, FLA_Obj &p );

      extern Int_ lu_nopiv     ( FLA_Obj &A );
      extern Int_ lu_piv       ( FLA_Obj &A, FLA_Obj &p );

      extern Int_ qr           ( FLA_Obj &A, FLA_Obj &T );
    }
  }
}
#endif
